package org.atlantis.ymer.server;

import java.util.HashMap;
import java.util.Map;

import org.atlantis.ymer.Transport;
import org.atlantis.ymer.WebSessionFactory;
import org.atlantis.ymer.common.HttpResponseUtils;
import org.atlantis.ymer.server.transport.HttpStreamingTransport;
import org.atlantis.ymer.server.transport.LongPollingTransport;
import org.atlantis.ymer.server.transport.TestTransport;
import org.atlantis.ymer.server.transport.WebSocketTransport;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.QueryStringDecoder;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

class ConnectorHandler extends SimpleChannelUpstreamHandler {

	private static final Logger log = LoggerFactory.getLogger(ConnectorHandler.class);
	private Map<String, Transport> transportMapping = new HashMap<String, Transport>();

	ConnectorHandler(WebSessionFactory sessionFactory) {
		transportMapping.put("websocket", new WebSocketTransport().set(sessionFactory));
		transportMapping.put("httpstreaming", new HttpStreamingTransport().set(sessionFactory));
		transportMapping.put("longpolling", new LongPollingTransport().set(sessionFactory));
		// TODO remove it before release
		transportMapping.put("test", new TestTransport());
	}

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
		Object message = e.getMessage();
		if (message instanceof HttpRequest) {
			handleHttpRequest(ctx, (HttpRequest) message);
		} else if (message instanceof WebSocketFrame) {
			handleWebSocket(ctx, (WebSocketFrame) message);
		}
	}

	private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest request) {
		String path = new QueryStringDecoder(request.getUri()).getPath();
		String pathParts[] = path.split("/");
		if (pathParts.length < 3 && !"ymer".equals(pathParts[1])) {
			log.warn("Unknow uri path: {}.", path);
			HttpResponseUtils.sendForbiddenHttpResponse(ctx.getChannel(), request);
			return;
		}
		Transport transport = transportMapping.get(pathParts[2]);
		if (transport == null) {
			log.warn("Unkonw transport id: {}", pathParts[2]);
			HttpResponseUtils.sendForbiddenHttpResponse(ctx.getChannel(), request);
			return;
		}
		transport.handle(ctx, request);
	}

	private void handleWebSocket(ChannelHandlerContext ctx, WebSocketFrame frame) {
		transportMapping.get("websocket").handle(ctx, frame);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
		log.error(ctx.getChannel() + " occur exception", e.getCause());
		ctx.getChannel().close();
	}
}